package com.dana1.nos.impl;


import static org.junit.Assert.*;

import java.util.Collection;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.dana1.nos.data.AddressBaseForMOS;
import com.dana1.nos.data.Primary;
import com.dana1.nos.data.Secondary;
import com.dana1.nos.data.User;
import com.dana1.nos.old.impl.memory.MemoryObjectService;
import com.dana1.nos.old.util.HardMemoizer;

public class TestMemoryObjectService extends TestAbstractObjectService
{
	private static final boolean debugMemoizer = false;
	
	@Before
	public void setUp() throws Exception
	{
		os = new MemoryObjectService();
		((MemoryObjectService)os).setAutoInsertServiceObjects(false);
		if (debugMemoizer)
			HardMemoizer.setDebugStream(System.err);
	}
	@After
	public void tearDown() throws Exception
	{
		if (debugMemoizer)
			HardMemoizer.setDebugStream(null);
	}

	@Test
	public void indirectFieldsWork()
	{
		Secondary s = os.newInstance(Secondary.class);
		s = os.retrieve(os.insert(s));
		Primary p = os.newInstance(Primary.class);
		p.setSecondary(s);
		assertEquals(s, p.getSecondary());
	}
	
	@Test(expected=UnsupportedOperationException.class)
	public void indexedCollectionWithoutInverseFailsBeforeInsert()
	{
		AddressBaseForMOS addressBase = os.newInstance(AddressBaseForMOS.class);
		try
		{
			addressBase = (AddressBaseForMOS)os.retrieve(os.insert(addressBase));
			addressBase.getUsersAtAddress();
			addressBase = os.newInstance(AddressBaseForMOS.class);
		} catch (Exception e)
		{
			throw new RuntimeException(e.getMessage(),e);
		}
		addressBase.getUsersAtAddress(); // this should fail since addressBase is not yet inserted
		fail("should not get here");
	}

	@Test(expected=UnsupportedOperationException.class)
	public void indexedCollectionWithoutInverseFailsInsertingUnconnected()
	{
		AddressBaseForMOS addressBase = os.newInstance(AddressBaseForMOS.class);
		addressBase = (AddressBaseForMOS)os.retrieve(os.insert(addressBase));
		
		Collection<User> users = addressBase.getUsersAtAddress();
		User u = os.newInstance(User.class);
		users.add(u);
		fail("should not get here");
	}

	@Test
	public void indexedCollectionWithoutInverseWorks()
	{
		AddressBaseForMOS addressBase = os.newInstance(AddressBaseForMOS.class);
		addressBase = (AddressBaseForMOS)os.retrieve(os.insert(addressBase));
		
		User u = os.newInstance(User.class);
		u = (User)os.retrieve(os.insert(u));

		Collection<User> users = addressBase.getUsersAtAddress();
		users.add(u);
		User u2 = addressBase.getUsersAtAddress().iterator().next();
		assertEquals(u2, u);
		users.add(u);
		users.add(u);
		users.add(u);
		assertEquals(4, users.size());

		
		Secondary s1 = os.newInstance(Secondary.class);
		s1 = os.retrieve(os.insert(s1));
		Secondary s2 = os.newInstance(Secondary.class);
		s2 = os.retrieve(os.insert(s2));
		Secondary s3 = os.newInstance(Secondary.class);
		s3 = os.retrieve(os.insert(s3));
		
		Primary p = os.newInstance(Primary.class);
		p = os.retrieve(os.insert(p));
		Collection<Secondary> secondaries = p.getSecondaries();
		secondaries.add(s1);
		secondaries.add(s2);
		secondaries.add(s3);
		assertEquals(3,secondaries.size());
		secondaries.add(s3);
		assertEquals(4,secondaries.size());
		secondaries.remove(s3);
		assertEquals(3,secondaries.size());
		
		assertTrue(secondaries.contains(s1));
		assertTrue(secondaries.contains(s2));
		assertTrue(secondaries.contains(s3));

		secondaries.clear();
		assertEquals(0,secondaries.size());

		boolean failed = false;
		try
		{
			p = os.newInstance(Primary.class);
			p.getSecondaries();
		}
		catch (UnsupportedOperationException uoe)
		{
			failed = true;
		}
		assertTrue(failed);
		
		
	}
	
	@Test
	public void indexedCollectionsWithNonCollectionInverseWorks()
	{
		Secondary s1 = os.newInstance(Secondary.class);
		s1 = os.retrieve(os.insert(s1));
		Secondary s2 = os.newInstance(Secondary.class);
		s2 = os.retrieve(os.insert(s2));
		Secondary s3 = os.newInstance(Secondary.class);
		s3 = os.retrieve(os.insert(s3));
		
		Primary p = os.newInstance(Primary.class);
		p = os.retrieve(os.insert(p));
		Collection<Secondary> secondaries = p.getSecondaryM1();
		secondaries.add(s1);
		secondaries.add(s2);
		secondaries.add(s3);
		assertEquals(3,secondaries.size());
		assertTrue(secondaries.contains(s1));
		assertTrue(secondaries.contains(s2));
		assertTrue(secondaries.contains(s3));
		secondaries.add(s3);
		assertEquals(3,secondaries.size());
		secondaries.remove(s3);
		assertFalse(secondaries.contains(s3));
		assertEquals(2,secondaries.size());
		
		assertTrue(secondaries.contains(s1));
		assertTrue(secondaries.contains(s2));

		secondaries.clear();
		assertEquals(0,secondaries.size());
	}
	
	@Test
	public void indexedCollectionsWithCollectionInverseWorks()
	{
		Secondary s1 = os.newInstance(Secondary.class);
		s1 = os.retrieve(os.insert(s1));
		Secondary s2 = os.newInstance(Secondary.class);
		s2 = os.retrieve(os.insert(s2));
		Secondary s3 = os.newInstance(Secondary.class);
		s3 = os.retrieve(os.insert(s3));
		
		Primary p1 = os.newInstance(Primary.class);
		p1 = os.retrieve(os.insert(p1));
		Primary p2 = os.newInstance(Primary.class);
		p2 = os.retrieve(os.insert(p2));

		Collection<Secondary> p1mm = p1.getSecondaryMM();
		Collection<Secondary> p2mm = p2.getSecondaryMM();
		Collection<Primary> s1mm = s1.getPrimaryMM();
		System.out.println(p1);
		p1mm.add(s1);
		p1mm.add(s2);
		p1mm.add(s3);
		assertEquals(3, p1mm.size());
		assertEquals(1, s1mm.size());
		s1mm.add(p2);
		assertEquals(2, s1mm.size());
		assertEquals(1, p2mm.size());
		
		p1mm.add(s3);
		assertEquals(4,p1mm.size());
		p1mm.remove(s3);
		assertEquals(3,p1mm.size());
		
		assertTrue(p1mm.contains(s1));
		assertTrue(p1mm.contains(s2));
		assertTrue(p1mm.contains(s3));

		p1mm.clear();
		assertEquals(0, p1mm.size());
		assertEquals(1, s1mm.size());
		assertEquals(1, p2mm.size());
		System.out.println(p1mm);
		System.out.println(p2mm);
		System.out.println(s1mm);
	}

	@Test
	public void indirectFieldWith11RelationWorks()
	{
		
		Secondary s1 = os.newInstance(Secondary.class);
		s1 = os.retrieve(os.insert(s1));
		Secondary s2 = os.newInstance(Secondary.class);
		s2 = os.retrieve(os.insert(s2));
		
		Primary p1 = os.newInstance(Primary.class);
		p1 = os.retrieve(os.insert(p1));
		Primary p2 = os.newInstance(Primary.class);
		p2 = os.retrieve(os.insert(p2));

		p2.setSecondary11(s2);
		assertEquals(s2,p2.getSecondary11());
		assertEquals(p2,s2.getPrimary11());
		p1.setSecondary11(s2);
		assertEquals(s2,p1.getSecondary11());
		assertEquals(p1,s2.getPrimary11());
		assertNull(p2.getSecondary11()); 
		p1.setSecondary11(s1);
		assertEquals(s1,p1.getSecondary11());
		assertEquals(p1,s1.getPrimary11());
		assertNull(s2.getPrimary11()); 
	}
	
	

}
